#!/usr/bin/env bash

source ../../lib/shell/common.sh

function get_online_cpu() {
    local value

    check_cmd "tree"
    for cpu in $(tree -d -i --noreport ${CPU_PATH} |grep -wE "cpu[0-9]+");do
        value=$(cat ${CPU_PATH}/${cpu}/online)
        [ $value -eq 1 ] && {
            CPU_ONLINE_NUMS=$[$CPU_ONLINE_NUMS+1]
            CPU_ONLINE_NAME="${CPU_ONLINE_NAME}${cpu} "
        }
    done
    if [ -z "$CPU_ONLINE_NUMS" ] || [ -z "$CPU_ONLINE_NAME" ];then
        echo "warning: No cpu is online." && return 1
    else
        echo "Get online cpu nums: $CPU_ONLINE_NUMS." && return 0
    fi
}

function cpuload_monitor_on_usr() {
    local cpu_nums=$1
    local has_cpu_on_off_during_stress=${2:-"false"}
    local count=0
    local cur_name
    local usr_ratio

    check_cmd "mpstat"
    echo "==================[CPULOAD monitor $(($RUNTIME - 10 ))s]===================" >> $CPU_LOAD_RESULTS_LOG

    mpstat -P ALL 1 $(($RUNTIME - 10 ))|grep "Average"|grep -ivE "CPU" > $CPU_LOAD_LOG
    if test ! -f $CPU_LOAD_LOG || test ! -s $CPU_LOAD_LOG;then
        echo "Error: no such file $CPU_LOAD_LOG,failed to get Monitoring information by mpstat." && exit 1
    fi
    while read line;do
        usr_ratio="$(echo "$line"|awk '{print $3}')"
        if "$has_cpu_on_off_during_stress";then
            if [ $(echo "$usr_ratio > 20"|bc) -eq 1 ];then
                ((count++))
                cur_name="${cur_name}cpu$(echo $line|awk '{print $2}') "
            fi
        else
            if [ $(echo "$usr_ratio > 90"|bc) -eq 1 ];then
                ((count++))
                cur_name="${cur_name}cpu$(echo $line|awk '{print $2}') "
            fi
        fi
    done < $CPU_LOAD_LOG

    #Deviation 5%
    all_average="$(grep all $CPU_LOAD_LOG|awk '{print $3}')"
    error_num="$(echo "scale=3;($cpu_nums - $count)/$cpu_nums"|bc)"
    if [ $count -ge $cpu_nums ] || [ $(echo "$error_num < 0.05"|bc) -eq 1 ] || [ $(top -H -b -n1|grep -w stress-ng-cpu|wc -l) -ge $cpu_nums ] \
        || (! $has_cpu_on_off_during_stress && [ $(echo "$all_average > 90"|bc) -eq 1 ]) || ( $has_cpu_on_off_during_stress && [ $(echo "$all_average > 20"|bc) -eq 1 ]) ;then
        echo -e "[CPU FULL lOAD(100.00%),AVERAGE(>20% or 90%),Deviation 5%]: count($count)--->cpu used($cpu_nums)\n$cur_name" >> $CPU_LOAD_RESULTS_LOG
        echo "Average:     CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle" >> $CPU_LOAD_RESULTS_LOG
        cat $CPU_LOAD_LOG >> $CPU_LOAD_RESULTS_LOG
    else
        echo "Error: cpu full load is $count,but it Should be $cpu_nums on monitor $CPU_LOAD_LOG" >> $CPU_LOAD_RESULTS_LOG
        echo "============[cpu load log]========================" >> $CPU_LOAD_RESULTS_LOG
        echo "Average:     CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle" >> $CPU_LOAD_RESULTS_LOG
        cat $CPU_LOAD_LOG >> $CPU_LOAD_RESULTS_LOG
        echo -e "============[cpu load log]========================\n" >> $CPU_LOAD_RESULTS_LOG
    fi
}

function cpu_stress_test() {
    local cpu_online_nums_half
    local jobs_info=""
    local cpu_used=""
    local average_cpu_used=""
    local pid=""
    local cur_time=0
    local cur_time_diff=0
    local cpu_used_count=0

    echo "============[$CPU_TEST_TYPE test]============"
    get_online_cpu
    if [ $CPU_ONLINE_NUMS -eq 0 ];then
        echo "Error: there are no online cpus." && exit 1
    elif [ $CPU_ONLINE_NUMS -eq 1 ]; then
        cpu_online_nums_half=$CPU_ONLINE_NUMS
    else
        cpu_online_nums_half=$(echo "$CPU_ONLINE_NUMS/2"|bc)
    fi

    [ X"$CPU_TEST_TYPE" = X"cpuburn" ] && echo "warning: cpuburn--->https://patrickmn.com/projects/cpuburn/"
    [ X"$CPU_TEST_TYPE" = X"mprime" ] && echo "warning: mprime--->https://mersenneforum.org/gimps/"
    check_cmd "$CPU_TEST_TYPE"
    cur_time="$(date +%s -d "$(date +"%a %b %e %T %Y")")"

    [ -n "$(pidof $CPU_TEST_TYPE)" ] && kill -9 $(pidof $CPU_TEST_TYPE)
    if [ X"$CPU_TEST_TYPE" = X"cpuburn" ];then
        nohup $CPU_TEST_TYPE -n $cpu_online_nums_half -u 5 >$CPU_STRESS_TEST_LOG &
    else
        nohup $CPU_TEST_TYPE -t >$CPU_STRESS_TEST_LOG &
    fi
    [ $? -eq 0 ] && pid=$! || return $?

    while (($cur_time_diff <= $CPU_RUNTIME));do
        sleep 10
        cur_time_diff=$(($(date +%s -d "$(date +"%a %b %e %T %Y")") - $cur_time))
        echo "[$CPU_TEST_TYPE] :Have been waiting ${cur_time_diff}s--->[runtime ${CPU_RUNTIME}s]."
        if [ $(($cur_time_diff + 10 )) -ge $CPU_RUNTIME ];then
            echo
            top -H -b -p $pid -n1
            average_cpu_used=$(top -H -b -p $pid -n1|grep "$CPU_TEST_TYPE"|awk '{{num=$(NF-3)}if(num == 0.0){n+=1}else{a+=$(NF-3)}} END {print a/(NR-n)}')
            echo "check $CPU_TEST_TYPE."
            echo "[CPU AVERAGE USED(1/2)]: $average_cpu_used"
            while read tpline;do
                ((cpu_used_count+=1))
                [ -z "$tpline" ] && continue
                cpu_used=$(echo $tpline|awk '{print $(NF-3)}')
                [ $? -ne 0 ] && { echo $tpline;continue; }
                if test "$cpu_used" == "0.0" || [ $(echo "$cpu_used < $(echo "$average_cpu_used / 2"|bc)" |bc) -eq 1 ];then
                    ((cpu_used_count-=1))
                else
                    jobs_info="${jobs_info}$(echo $tpline|awk '{print $1"_"$NF"_"$(NF-3)"(%CPU)"}')\n"
                fi
            done << EOF
            `top -b -H -p $pid -n1|grep $CPU_TEST_TYPE`
EOF
            if pidof $CPU_TEST_TYPE >/dev/null 2>&1;then
                kill -9 `pidof $CPU_TEST_TYPE`
            fi
            while read line;do echo $line ;done < $CPU_STRESS_TEST_LOG
            echo -e $jobs_info
            echo "[CPU USED COUNT]: $cpu_used_count"
            echo "[CPU USED GE AVERAGE USED COUNT]: $(echo -e $jobs_info | grep -c "$CPU_TEST_TYPE")"
            if [ $(echo -e $jobs_info | grep -c "$CPU_TEST_TYPE") -ge $cpu_used_count ];then
                return 0
            fi
            return 1
        fi
    done
}
